package ar.edu.caece.pl.asem.model.impl.treeelements;

import ar.edu.caece.pl.asem.model.impl.SymbolTable;
import ar.edu.caece.pl.asem.temp.TemporalGenerator;
import ar.edu.caece.pl.asin.manager.impl.ErrorManager;

public class Funcion extends MetodoGenerico {

	private int tempResultFun;

	public Funcion(String name) {
		this.name = name;
		this.label = "FUNCION";
	}

	public int getTemp() {
		return tempResultFun;
	}

	public void setTemp(int tempResultFun) {
		this.tempResultFun = tempResultFun;
	}

	@Override
	public String toString() {
		return this.getLabel()
				+ ": "
				+ this.getName()
				+ "() : "
				+ SymbolTable.getInstance()
						.getVerboseType(this.getReturnType());
	}

	@Override
	public void generateASMCode() {
		StringBuffer sb = new StringBuffer();
		if (ErrorManager.debugEnabled) sb.append(TAB + "; Func-init" + ENTER);
		
		// Guardo el Metodo actual, para luego guardar el ambiente en la pila
		TemporalGenerator.getInstance().checkPointActualMethod(this);
		
		
		String procedureName = this.getName();
		sb.append(procedureName + " proc near" + ENTER);
		
		/*
		 * this.getChildren().get(0) = Parametros 
		 * this.getChildren().get(1) = Declaraciones
		 * this.getChildren().get(2) = ReturnType
		 * this.getChildren().get(3) = Cuerpo
		 * 
		 */

		if (this.getChildren().size() > 1) {

			// <PARAMETROS>
			// Se tiene que hacer un push porque es el retorno de la funcion, despues vienen los parametros!!!
			sb.append("\t push bp \n");
			sb.append("\t mov bp, sp \n");
			
			// Reservar espacio en memoria para variables locales si las tiene!
			if(this.getChildren().get(1).getChildren().size()>0){
				int spaceForLocalVariables = this.getChildren().get(1).getChildren().size() * 2;
				sb.append("\t sub sp, " + spaceForLocalVariables + "\n");
			}
			
			// <DECLARACION DE VARIABLES LOCALES>
			this.getChildren().get(1).generateASMCode();
			sb.append(this.getChildren().get(1).code);
			
			// <CUERPO>
			if (ErrorManager.debugEnabled) sb.append(TAB + "; Func-Cuerpo-init" + ENTER);

			this.getChildren().get(3).generateASMCode();
			sb.append(this.getChildren().get(3).code);

			if (ErrorManager.debugEnabled) sb.append(TAB + "; Func-Cuerpo-finish" + ENTER);

			// <RETURN TYPE>
			if (ErrorManager.debugEnabled) sb.append(TAB + "; Func-returnType-init" + ENTER);

			this.getChildren().get(2).generateASMCode();
			//TemporalGenerator.getInstance().releaseTemporal();
			sb.append(this.getChildren().get(2).code);
			sb.append(TAB + "mov sp, bp" + ENTER);
			sb.append(TAB + "pop bp" + ENTER);
			sb.append(TAB + "ret" + ENTER);

			if (ErrorManager.debugEnabled) sb.append(TAB + "; Func-returnType-finish" + ENTER);
		}

		sb.append(procedureName + " endp" + ENTER);
		if (ErrorManager.debugEnabled) sb.append(TAB + "; Func-End" + ENTER);

		this.code = sb.toString();
	}

}
